package com.alexvas.rtsp.codec.renderer

import android.graphics.SurfaceTexture
import android.opengl.GLES20
import android.os.Looper
import android.util.Log
import android.view.Surface
import java.util.logging.Handler

class VideoRenderThread(
    private val outputSurfaceTexture: SurfaceTexture,
    private val viewW: Int,
    private val viewH: Int,
    private val codeSurfaceCreatedCallBack: (Surface) -> Unit
) : Thread("VideoRenderThread") {

    private lateinit var eglCore: EGLCore
    private var oesTexId = 0
    private var inputSurfaceTexture: SurfaceTexture? = null
    var codecSurface: Surface? = null
        private set
    private val texMatrix = FloatArray(16)
    @Volatile private var frameAvailable = false
    private val frameLock = Object()
    private val renderer = OesRenderer()

    override fun run() {
        try {
            eglCore = EGLCore(outputSurfaceTexture)
            Log.d("VideoRender", "EGL created, making OES texture")
            oesTexId = GlUtil.createOesTexture()
            if (oesTexId == 0) throw RuntimeException("createOesTexture failed")

            // input surface tied to the OES texture
            inputSurfaceTexture = SurfaceTexture(oesTexId)

            // listener: use main looper handler to avoid missing callbacks on some devices
            inputSurfaceTexture?.setOnFrameAvailableListener({
                synchronized(frameLock) {
                    frameAvailable = true
                    frameLock.notifyAll()
                }
            })

            codecSurface = Surface(inputSurfaceTexture)
            codeSurfaceCreatedCallBack.invoke(codecSurface!!)
            renderer.init()
            Log.d("VideoRender", "Renderer initialized, codecSurface ready")

            while (!isInterrupted) {
                synchronized(frameLock) {
                    if (!frameAvailable) {
                        frameLock.wait(200) // wake periodically
                    }
                    frameAvailable = false
                }

                // Must update on the GL thread with current context
                inputSurfaceTexture?.let { st ->
                    st.updateTexImage()
                    st.getTransformMatrix(texMatrix)
                    val ts = st.timestamp
//                    Log.v("VideoRender", "updateTexImage ts=$ts")
                    renderer.draw(oesTexId, texMatrix, viewW, viewH)
                    eglCore.swapBuffers()
                }
            }
        } catch (e: InterruptedException) {
            // normal exit
        } catch (t: Throwable) {
            Log.e("VideoRender", "Render thread error", t)
        } finally {
            try { codecSurface?.release() } catch (e: Exception) {}
            try { inputSurfaceTexture?.release() } catch (e: Exception) {}
            try { renderer.release() } catch (e: Exception) {}
            try { eglCore.release() } catch (e: Exception) {}
            Log.d("VideoRender", "Render thread exiting")
        }
    }

    fun releaseThread() {
        interrupt()
        synchronized(frameLock) { frameLock.notifyAll() }
    }
}

